package com.xyzh05.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.compass.annotations.Searchable;
import org.compass.annotations.SearchableId;
import org.compass.annotations.SearchableProperty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.xyzh05.util.DateUtil;

@Entity
@Table(name="app_user")
@Searchable
@XmlRootElement
public class User extends BaseObject implements Serializable, UserDetails {
	private static final long serialVersionUID = -2030969321964899913L;
	
	/** 正常状态 */
	public static final Short STATUS_NORMAL = 0;
	/** 锁定状态 */
	public static final Short STATUS_LOCKED = 1;
	/** 过期状态 */
	public static final Short STATUS_EXPIRED = 2;
	/** 无效状态 */
	public static final Short STATUS_DISABLED = 4;
	
	/**保密*/
	public static final Short GENDER_UNKNOWN = 0;
	/** 男 */
	public static final Short GENDER_MALE = 1;
	/** 女 */
	public static final Short GENDER_FEMALE = 2;
	
    private Long id;
    private Long version;
    private String username;
    private String password;
    private String confirmPassword;
    private String displayName;
    private String description;
    private Short gender = GENDER_UNKNOWN;
    private String email;
    private String mobilephone;
    private Date regTime = DateUtil.getNow();
    private Short regMode = LoginLog.MODE_PC;
    private Long roleId = Role.DEFAULT_ROLE_USER;
    private Short status = STATUS_NORMAL;
    private Boolean credentialsExpired = Boolean.FALSE;
    private UserInfo userInfo = new UserInfo();
    private Set<Role> roles = new HashSet<Role>(0);
    private Set<Notepad> notepads = new HashSet<Notepad>(0);
    
    /**
     * Default constructor - creates a new instance with no values set.
     */
    public User() {
    }

    /**
     * Create a new instance and set the username.
     *
     * @param username login name for user.
     */
    public User(final String username) {
        this.username = username;
    }
    
    @Id @GeneratedValue(strategy=GenerationType.AUTO) @SearchableId    
    public Long getId() {
        return this.id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    @Version
    @Column(name="version")
    @SearchableProperty
    public Long getVersion() {
        return this.version;
    }
    
    public void setVersion(Long version) {
        this.version = version;
    }
    
    @Column(name="username", nullable=false, length=32)
    @SearchableProperty
    public String getUsername() {
        return this.username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    @Column(name="password", nullable=false, length=64)
    @SearchableProperty
    public String getPassword() {
        return this.password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Transient @XmlTransient
    public String getConfirmPassword() {
        return confirmPassword;
    }
    
    public void setConfirmPassword(String confirmPassword) {
        this.confirmPassword = confirmPassword;
    }
    
    @Column(name="display_name", nullable=false, length=16)
    @SearchableProperty
    public String getDisplayName() {
        return this.displayName;
    }
    
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }
    
    @Column(name="description", length=128)
    @SearchableProperty
    public String getDescription() {
        return this.description;
    }
    
    public void setDescription(String description) {
        this.description = description;
    }
    
    @Column(name="gender", nullable=false)
    @SearchableProperty
    public Short getGender() {
        return this.gender;
    }
    
    public void setGender(Short gender) {
        this.gender = gender;
    }
    
    @Column(name="email", nullable=false, length=32)
    @SearchableProperty
    public String getEmail() {
        return this.email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    @Column(name="mobilephone", length=16)
    @SearchableProperty
    public String getMobilephone() {
        return this.mobilephone;
    }
    
    public void setMobilephone(String mobilephone) {
        this.mobilephone = mobilephone;
    }
    
	@Temporal(TemporalType.TIMESTAMP)
    @Column(name="reg_time", nullable=false, length=19)
    @SearchableProperty
    public Date getRegTime() {
        return this.regTime;
    }
    
    public void setRegTime(Date regTime) {
        this.regTime = regTime;
    }
    
    @Column(name="reg_mode", nullable=false)
    @SearchableProperty
    public Short getRegMode() {
        return this.regMode;
    }
    
    public void setRegMode(Short regMode) {
        this.regMode = regMode;
    }
    
    @Column(name="role_id", nullable=false)
    @SearchableProperty
    public Long getRoleId() {
        return this.roleId;
    }
    
    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }
    
    @Column(name="status", nullable=false)
    @SearchableProperty
    public Short getStatus() {
        return this.status;
    }
    
    public void setStatus(Short status) {
        this.status = status;
    }
    
    @Column(name = "credentials_expired", nullable = false)
	public Boolean isCredentialsExpired() {
		return credentialsExpired;
	}

	public void setCredentialsExpired(Boolean credentialsExpired) {
		this.credentialsExpired = credentialsExpired;
	}
	
    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="user")
    public UserInfo getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(UserInfo userInfo) {
		this.userInfo = userInfo;
	}

	@ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinTable(name="user_role", joinColumns = { 
    @JoinColumn(name="user_id", nullable=false, updatable=false) }, inverseJoinColumns = { 
    @JoinColumn(name="role_id", nullable=false, updatable=false) })
    public Set<Role> getRoles() {
        return this.roles;
    }
    
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
    
	@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="user")
    public Set<Notepad> getNotepads() {
		return notepads;
	}

	public void setNotepads(Set<Notepad> notepads) {
		this.notepads = notepads;
	}

	/**
     * 获得用户角色
     * @return
     */
    @Transient
    public Role getMainRole(){
    	Role role = null;
    	for (Role r : roles) {
    		role = r;
    		break;
    	}
    	return role;
    }

    @Transient
    public Boolean isAdminRole(){
    	return Role.DEFAULT_ROLE_ADMIN == getMainRole().getRoleType().getId();
    }

    @Transient
    public Boolean isUserRole(){
    	return Role.DEFAULT_ROLE_USER == getMainRole().getRoleType().getId();
    }

    @Transient
    public Boolean isEmployeeRole(){
    	return Role.DEFAULT_ROLE_EMPLOYEE == getMainRole().getRoleType().getId();
    }

    @Transient
    public Boolean isCompanyRole(){
    	return Role.DEFAULT_ROLE_COMPANY == getMainRole().getRoleType().getId();
    }

    @Transient
	public Department getUserDepartment() {
		return getMainRole().getDepartment();
	}
    
    /**
     * Convert user roles to LabelValue objects for convenience.
     *
     * @return a list of LabelValue objects with role information
     */
    @Transient
    public List<LabelValue> getRoleList() {
        List<LabelValue> userRoles = new ArrayList<LabelValue>();

        if (this.roles != null) {
            for (Role role : roles) {
                // convert the user's roles to LabelValue Objects
                userRoles.add(new LabelValue(role.getName(), role.getName()));
            }
        }

        return userRoles;
    }

    /**
     * Adds a role for the user
     *
     * @param role the fully instantiated role
     */
    public void addRole(Role role) {
        getRoles().add(role);
    }

    /**
     * @return GrantedAuthority[] an array of roles.
     * @see org.springframework.security.core.userdetails.UserDetails#getAuthorities()
     */
    @Transient
    public Set<GrantedAuthority> getAuthorities() {
        Set<GrantedAuthority> authorities = new LinkedHashSet<GrantedAuthority>();
        authorities.addAll(roles);
        return authorities;
    }

	private boolean checkBit(Short checker) {
		return (status.shortValue() & checker.shortValue()) > 0;
	}
	
	/**
     * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonExpired()
     * @return true if account is still active
     */
    @Transient
	public boolean isAccountNonExpired() {
		return !checkBit(STATUS_EXPIRED);
	}

    /**
     * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonLocked()
     * @return false if account is locked
     */
    @Transient
	public boolean isAccountNonLocked() {
		return !checkBit(STATUS_LOCKED);
	}

    /**
     * @see org.springframework.security.core.userdetails.UserDetails#isCredentialsNonExpired()
     * @return true if credentials haven't expired
     */
    @Transient
	public boolean isCredentialsNonExpired() {
		return !isCredentialsExpired();
	}

    /**
     * @see org.springframework.security.core.userdetails.UserDetails#isCredentialsNonExpired()
     * @return true if credentials haven't expired
     */
    @Transient
	public boolean isEnabled() {
		return !checkBit(STATUS_DISABLED);
	}

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User pojo = (User) o;

        if (version != null ? !version.equals(pojo.version) : pojo.version != null) return false;
        if (username != null ? !username.equals(pojo.username) : pojo.username != null) return false;
        if (password != null ? !password.equals(pojo.password) : pojo.password != null) return false;
        if (displayName != null ? !displayName.equals(pojo.displayName) : pojo.displayName != null) return false;
        if (description != null ? !description.equals(pojo.description) : pojo.description != null) return false;
        if (gender != null ? !gender.equals(pojo.gender) : pojo.gender != null) return false;
        if (email != null ? !email.equals(pojo.email) : pojo.email != null) return false;
        if (mobilephone != null ? !mobilephone.equals(pojo.mobilephone) : pojo.mobilephone != null) return false;
        if (regTime != null ? !regTime.equals(pojo.regTime) : pojo.regTime != null) return false;
        if (regMode != null ? !regMode.equals(pojo.regMode) : pojo.regMode != null) return false;
        if (roleId != null ? !roleId.equals(pojo.roleId) : pojo.roleId != null) return false;
        if (status != null ? !status.equals(pojo.status) : pojo.status != null) return false;
        if (credentialsExpired != null ? !credentialsExpired.equals(pojo.credentialsExpired) : pojo.credentialsExpired != null) return false;

        return true;
    }

    public int hashCode() {
        int result = 0;
        result = (version != null ? version.hashCode() : 0);
        result = 31 * result + (username != null ? username.hashCode() : 0);
        result = 31 * result + (password != null ? password.hashCode() : 0);
        result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
        result = 31 * result + (description != null ? description.hashCode() : 0);
        result = 31 * result + (gender != null ? gender.hashCode() : 0);
        result = 31 * result + (email != null ? email.hashCode() : 0);
        result = 31 * result + (mobilephone != null ? mobilephone.hashCode() : 0);
        result = 31 * result + (regTime != null ? regTime.hashCode() : 0);
        result = 31 * result + (regMode != null ? regMode.hashCode() : 0);
        result = 31 * result + (roleId != null ? roleId.hashCode() : 0);
        result = 31 * result + (status != null ? status.hashCode() : 0);
        result = 31 * result + (credentialsExpired != null ? credentialsExpired.hashCode() : 0);

        return result;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer(getClass().getSimpleName());

        sb.append(" [");
        sb.append("id").append("='").append(getId()).append("', ");
        sb.append("version").append("='").append(getVersion()).append("', ");
        sb.append("username").append("='").append(getUsername()).append("', ");
        sb.append("password").append("='").append(getPassword()).append("', ");
        sb.append("displayName").append("='").append(getDisplayName()).append("', ");
        sb.append("description").append("='").append(getDescription()).append("', ");
        sb.append("gender").append("='").append(getGender()).append("', ");
        sb.append("email").append("='").append(getEmail()).append("', ");
        sb.append("mobilephone").append("='").append(getMobilephone()).append("', ");
        sb.append("regTime").append("='").append(getRegTime()).append("', ");
        sb.append("regMode").append("='").append(getRegMode()).append("', ");
        sb.append("roleId").append("='").append(getRoleId()).append("', ");
        sb.append("status").append("='").append(getStatus()).append("', ");
        sb.append("credentialsExpired").append("='").append(isCredentialsExpired()).append("', ");
        
        sb.append("]");
      
        return sb.toString();
    }

}
